"""第15节，面向对象进阶
魔术方法之实例化
魔术方法之可视化
魔术方法之布尔等效
魔术方法之比较运算符重载
魔术方法之算数运算符重载
魔术方法之容器化
第16节，面向对象进阶
魔术方法之可调用对象
魔术方法之上下文管理
魔术方法之反射
模块搜索加载缓存导入和全局变量
魔术方法之哈希
包加载原理
绝对导入和相对导入
导入访问控制和__all__
打包分发
树的遍历

完成作业：


1.集合（set）元素去重的判断依据是什么
    第一步. 首先hash，不相同则可以确认互异
    第二步：如hash值相同，则调用__eq__比较
        class Foo:
            def __init__(self, name, value):
                self.name = name
                self.value = value

            def __hash__(self):
                print(f'{self.name}调用hash方法')
                return hash(self.value)

            def __eq__(self, other):
                print(f'{self.name}调用__eq__方法')
                print(self.__dict__)
                print(other.__dict__)
                return self.__dict__ == other.__dict__

        f1 = Foo('f1', 1)
        f2 = Foo('f2', 2)
        f3 = Foo('f3', 1)
        ls = [f1, f1]
        print('='*30)
        print(set(ls))

        ls = [f1, f3]
        print('#'*30)
        print(set(ls))

2.
总结本周视频讲解魔术方法的作用及什么情况会执行到该方法
    __new__:    类实例化时创建实例
    __init__:   类实例化之后，初始化数据
    __str__:    str()， print, format 函数调用，返回一个对象的字符串表达
    __repr__:   str()， print, format 函数调用，返回一个对象的字符串表达；函数调用方法顺序优先级：__str__ ==> __repr__ ==> 内存地址
    __bytes__:  bytes()函数调用，返回一个对象的bytes表达
    __bool__:   bool()函数调用，返回布尔值；
    __lt__, __le__, __eq__, __gt__, __ge__, __ne__:     比较运算符重载
    __add__, __sub__, __mul__, __truediv__, __mod__, __floordiv__, __pow__, __divmod__:   算数运算符重载
    __iadd__, __isub__, __imul__, __itruediv__, __imod__, __ifloordiv__, __ipow__
    __len__:    len()函数调用，返回对象长度
    __iter__:   迭代容器时，返回一个新的迭代器对象
    __contains__: in成员运算符，没有实现就调用__iter__遍历
    __getitem__:    实现self[key]
    __setitem__: self[key] = value 设置值的方法
    __missing__: 字段或其子类使用__getitem__(),key不存在时执行该方法
    __call__:   实现实例可以像函数一样调用；
    __enter__: 进入此对象相关的上下文。with会把该方法的返回值作为绑定到as子句中指定的变量上。
    __exit__:   退出与此对象相关的上下文时执行此语句

3.结合本周所学内容，实现如下类：

class Ob:
    pass


执行以下操作：
a = Ob('tom')
b = Ob('tom')
print('a: ', a)
a[0] = 'a'
print('a:', a)
a * 3
print('len: ', len(a))
del a[1]
print('a: ', a)
print('set: ', {a, b})

其输出如下：
a: ['1', '2']
a: ['a', '2']
len: 6
a: ['a', 'a', '2', 'a', '2']
set: { < Ob
name = tom
items = ['a', 'a', '2', 'a', '2'] >}"""



class Ob:

    def __init__(self, name):
        self.name = name
        self.list_val = ['1', '2']

    def __repr__(self):
        return f'{self.list_val}'

    def __getitem__(self, item):
        return self.list_val[item]

    def __setitem__(self, key, value):
        self.list_val[key] = value

    def __mul__(self, other):
        self.list_val *= other

    def __len__(self):
        return len(self.list_val)

    def __delitem__(self, key):
        self.list_val.pop(key)

    def __hash__(self):
        return hash(id(self.name))

    def __eq__(self, other):
        return self.name == other.name

a = Ob('tom')
b = Ob('tom')
print('a: ', a)
a[0] = 'a'
print('a:', a)
a * 3
print('len: ', len(a))
del a[1]
print('a: ', a)
print('set: ', {a, b})
